package cn.iocoder.yudao.module.biobee.utils;

import cn.iocoder.yudao.module.biobee.exception.ShellExecuteException;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class BioBeeUtils {

    private static final int TIMEOUT_MINUTES = 5;

    public static void createDirIfNotExist(String path) throws IOException {
        File dir = new File(path);
        if (!dir.exists() && !dir.mkdirs()) {
            throw new IOException("目录创建失败：" + path);
        }
    }
    public  static String buildPath(String... paths) {
        return String.join(File.separator, paths);
    }

    public static String execute(String command, String shellPath, String logPath) {
        try {
            writeShellScript(shellPath, command);
            return executeShellAndLog(shellPath, logPath);
        } catch (IOException | InterruptedException e) {
            throw new ShellExecuteException("Shell 执行异常: " + e.getMessage());
        }
    }

    /**
     * 写入 shell 脚本文件（带 shebang）。
     */
    private static void writeShellScript(String shellPath, String command) throws IOException {
        Path path = Paths.get(shellPath);
        Path parentDir = path.getParent();

        if (parentDir != null && !Files.exists(parentDir)) {
            Files.createDirectories(parentDir);
        }

        String scriptContent = "#!/bin/bash\n" + command;
        Files.write(path, scriptContent.getBytes(StandardCharsets.UTF_8));

        try {
            path.toFile().setExecutable(true);
        } catch (Exception e) {
            System.err.println("警告：无法设置脚本执行权限（可能为 Windows 系统）");
        }
    }

    private static String executeShellAndLog(String shellPath, String logPath) throws IOException, InterruptedException {
        Path logFile = Paths.get(logPath);
        Path logDir = logFile.getParent();
        if (logDir != null && !Files.exists(logDir)) {
            Files.createDirectories(logDir);
        }

        ProcessBuilder pb = new ProcessBuilder("bash", shellPath);
        pb.redirectErrorStream(true); // 合并 stdout 和 stderr
        pb.redirectOutput(ProcessBuilder.Redirect.to(logFile.toFile()));

        Process process = pb.start();

        boolean finished = process.waitFor(TIMEOUT_MINUTES, TimeUnit.MINUTES);
        if (!finished) {
            process.destroyForcibly();
            throw new ShellExecuteException("Shell 执行超时（" + TIMEOUT_MINUTES + "分钟）");
        }

        int exitCode = process.exitValue();
        String logContent = readLastLines(logFile, 50);

        if (exitCode != 0) {
            throw new ShellExecuteException("Shell 执行失败，退出码: " + exitCode + "\n日志部分内容:\n" + logContent);
        }

        return logContent;
    }


    /**
     * 读取日志文件的最后 N 行（用于错误提示或返回执行结果）
     */
    private static String readLastLines(Path filePath, int maxLines) {
        try {
            List<String> allLines = Files.readAllLines(filePath, StandardCharsets.UTF_8);
            int fromIndex = Math.max(allLines.size() - maxLines, 0);
            return String.join("\n", allLines.subList(fromIndex, allLines.size()));
        } catch (IOException e) {
            return "(无法读取日志内容)";
        }
    }

    public static void saveMultipartFile(MultipartFile file, Path targetDir) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IOException("上传文件不能为空");
        }
        // 原始文件名
        String filename = file.getOriginalFilename();
        if (filename == null) {
            throw new IOException("无法获取上传文件名");
        }

        try {
            // 3. 确保目录存在（递归创建）
            if (!Files.exists(targetDir)) {
                Files.createDirectories(targetDir);
            }

            // 4. 构造目标文件全路径
            Path targetFile = targetDir.resolve(filename);

            // 5. 将 MultipartFile 的流写入目标文件
            try (InputStream in = file.getInputStream();
                 OutputStream out = Files.newOutputStream(
                         targetFile,
                         StandardOpenOption.CREATE,
                         StandardOpenOption.TRUNCATE_EXISTING
                 )) {
                byte[] buffer = new byte[8192];
                int len;
                while ((len = in.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
            }
        } catch (IOException e) {
            throw new IOException("文件保存失败：" + e.getMessage(), e);
        }
    }
}
